package com.ugoodtech.mdcc.core.service.impl;

/* Copyright (C) Ugoodtech, Inc - All Rights Reserved.
* Unauthorized copying of this file, via any medium is strictly prohibited.
* Proprietary and confidential.
* Written by Stone Shaw.
*/


import com.google.common.collect.Lists;
import com.mysema.query.BooleanBuilder;
import com.ugoodtech.mdcc.core.domain.Nation;
import com.ugoodtech.mdcc.core.domain.QNation;
import com.ugoodtech.mdcc.core.repository.NationRepository;
import com.ugoodtech.mdcc.core.service.NationService;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
public class NationServiceImpl implements NationService {
    @Autowired
    private NationRepository nationRepository;


    @Override
    public Iterable<Nation> findAllProvinces(
    ) {
        QNation qNation = QNation.nation;
        BooleanBuilder builder = new BooleanBuilder();


//        builder.and(qNation.id.ne(1l));
        builder.and(qNation.province.isNotNull()).and(qNation.province.isNotEmpty());
        return nationRepository.findAll(builder, new Sort(Sort.Direction.ASC, "province"));

    }

    @Override
    public Iterable<Nation> findCitiesInProvince(
            String provinceCode) {
        QNation qNation = QNation.nation;
        BooleanBuilder builder = new BooleanBuilder();
        if (!StringUtils.isEmpty(provinceCode)) {
            builder.and(qNation.parent.code.eq(provinceCode));
        }

        builder.and(qNation.city.isNotNull()).and(qNation.city.isNotEmpty());
        return nationRepository.findAll(builder, new Sort(Sort.Direction.ASC, "city"));
    }

    @Override
    public Iterable<Nation> findDistrictsInCity(
            String cityCode) {
        QNation qNation = QNation.nation;
        BooleanBuilder builder = new BooleanBuilder();
        if (!StringUtils.isEmpty(cityCode)) {
            builder.and(qNation.parent.code.eq(cityCode));
        }


        builder.and(qNation.district.isNotNull()).and(qNation.district.isNotEmpty());
//        builder.and(qNation.district.ne("市辖区"));
        return nationRepository.findAll(builder, new Sort(Sort.Direction.ASC, "district"));
    }

    @Override
    public Iterable<Nation> findStreetsInDistrict(String districtCode) {
        QNation qNation = QNation.nation;
        BooleanBuilder builder = new BooleanBuilder();
        if (!StringUtils.isEmpty(districtCode)) {
            builder.and(qNation.parent.code.eq(districtCode));
        }


        builder.and(qNation.street.isNotNull()).and(qNation.street.isNotEmpty());
        return nationRepository.findAll(builder, new Sort(Sort.Direction.ASC, "street"));
    }

    @Override
    public Nation findByCode(String code) {
        QNation qNation = QNation.nation;
        BooleanBuilder builder = new BooleanBuilder();
        if (!StringUtils.isEmpty(code)) {
            builder.and(qNation.code.eq(code));
            builder.and(qNation.province.isEmpty());
        }
        Iterable<Nation> nations = nationRepository.findAll(builder, new Sort(Sort.Direction.ASC, "code"));
        if (null != nations) {
            for (Nation nation : nations) {
                return nation;
            }
        }
        return null;
    }

    @Override
    public Iterable<Nation> findByName(String name) {
        QNation qNation = QNation.nation;
        BooleanBuilder builder = new BooleanBuilder();
        if (!StringUtils.isEmpty(name)) {
            builder.and(qNation.district.eq(name));
            builder.and(qNation.province.isEmpty());
        }
        Iterable<Nation> nations = nationRepository.findAll(builder, new Sort(Sort.Direction.ASC, "code"));
        return nations;
    }

    @Override
    public Nation getByCode(String code) {
        List<Nation> nationList= nationRepository.findByCode(code);
        if (null!=nationList&&nationList.size()>0) {
            return nationList.get(0);
        }else {
            return null;
        }
    }
    @Override
    public List<Nation> getLocationByNameVOs(String name) throws Exception {
       return getLocationDOs("000000", null, name);
    }
    /**
     * Filter provinces, districts.
     *
     * @param parentId id of parent location.
     * @param code zip code.
     * @return list of location.
     */
    @Override
    public List<Nation> getLocationDOs(String code, Long parentId, String name) throws Exception {
        if (StringUtils.isBlank(code) && Objects.isNull(parentId)) {
            return new ArrayList<>(0);
        }
        List<Nation> locationDOList = null;
        BooleanBuilder booleanBuilder =new BooleanBuilder();
        QNation qNation =QNation.nation;

//        LocationDOExample example = new LocationDOExample();
//        LocationDOExample.Criteria criteria = example.or();
//        LocationDOExample.Criteria criteria1 = example.or();
        if (StringUtils.isNotEmpty(code)) {
            Nation locationDO = getLocationDO(code);
            if (Objects.isNull(locationDO)) {
                return new ArrayList<>(0);
            }
            booleanBuilder.and(qNation.parent.id.eq(locationDO.getId())).and(qNation.id.ne(locationDO.getId()));
            booleanBuilder.or(qNation.parent.id.eq(locationDO.getId())).and(qNation.id.ne(locationDO.getId()));
//            criteria.andParentEqualTo(locationDO.getId()).andIdNotEqualTo(locationDO.getId());
//            criteria1.andParentEqualTo(locationDO.getId()).andIdNotEqualTo(locationDO.getId());
        } else {
            if (!Objects.isNull(parentId)) {
                booleanBuilder.and(qNation.parent.id.eq(parentId)).and(qNation.id.ne(parentId));
                booleanBuilder.or(qNation.parent.id.eq(parentId)).and(qNation.id.ne(parentId));
//                criteria.andParentEqualTo(parentId).andIdNotEqualTo(parentId);
//                criteria1.andParentEqualTo(parentId).andIdNotEqualTo(parentId);
            }
        }
        if (StringUtils.isNotEmpty(name)) {
            booleanBuilder.and(qNation.province.like("%" + name + "%"));
            booleanBuilder.or(qNation.city.like("%" + name + "%"));
        }
        Iterable<Nation> all = nationRepository.findAll(booleanBuilder);
        locationDOList =  Lists.newArrayList(all);
//        locationDOList = locationDOMapperExt.selectByExample(example);
        // Set cache.
//			try {
//				redisUtil.set(cacheKey, JsonUtil.convertObjectToJson(locationDOList), 300);
//			} catch (JsonProcessingException e) {
//				log.warn("Convert json error.", e);
//			}
//		} else {
//			if (log.isDebugEnabled()) {
//				log.debug("Get locations by code [{}], parent id [{}] or name [{}] from cache.", code,
//						parentId, name);
//			}
//			// Convert cache string to json.
//			try {
//				locationDOList = JsonUtil.jsonToObj(cache.toString(),
//						new TypeReference<List<LocationDO>>() {
//						});
//			} catch (IOException e) {
//				log.warn("Convert json error.", e);
//			}
//		}
        return locationDOList;
    }
    /**
     * Get location info by its code.
     *
     * @param code district code
     * @return location info
     */
    private Nation getLocationDO(String code) throws Exception {
        if (StringUtils.isBlank(code)) {
            return null;
        }
        BooleanBuilder booleanBuilder =new BooleanBuilder();
        QNation qNation =QNation.nation;
        List<Nation> locationDOList = null;
//        LocationDOExample example = new LocationDOExample();
        if (Objects.equals("000000", code)) {
//            example.or().andCodeEqualTo(code);
            booleanBuilder.and(qNation.code.eq(code));
        } else {
            // Filter data which parent id is 1 to avoid redundant data.
            booleanBuilder.and(qNation.code.eq(code).and(qNation.parent.id.eq(1l)));
//            example.or().andCodeEqualTo(code).andParentEqualTo(1L);
        }
        Iterable<Nation> all = nationRepository.findAll(booleanBuilder);
        locationDOList =  Lists.newArrayList(all);
        if (CollectionUtils.isEmpty(locationDOList)) {
            return null;
        }
        if (locationDOList.size() > 1) {
            throw new Exception("Location data redundant for code [" + code + "]");
        }
//			// Set cache.
//			try {
//				redisUtil.set(cacheKey, JsonUtil.convertObjectToJson(locationDOList.get(0)), 300);
//			} catch (JsonProcessingException e) {
//				log.warn("Convert json error.", e);
//			}
//		} else {
//			if (log.isDebugEnabled()) {
//				log.debug("Get locations by code [{}] from cache.", code);
//			}
//			// Convert cache string to json.
//			try {
//				locationDOList = JsonUtil.jsonToObj(cache.toString(),
//						new TypeReference<List<LocationDO>>() {
//						});
//			} catch (IOException e) {
//				log.warn("Convert json error.", e);
//			}
//		}
        return locationDOList.get(0);
    }
}
